/*
* Polygon.java
* Author: Colin Ponce
* Written: 9/12/2010
*/

/**
 * @author Colin Ponce
 * @author Jeran Fox
 * 
 * 2010-09-12
 */

package geometry;

import geometry.ObjModel.Material;
import geometry.TriangleMesh.TriangleIndex;

import java.util.ArrayList;
import java.util.List;

import javax.media.opengl.GL2;
import javax.vecmath.Point3d;
import javax.vecmath.Point3f;
import javax.vecmath.TexCoord2f;
import javax.vecmath.Vector3f;

import util.Util;
import collision.BoundingBox;
import collision.BoundingSphere;

	
public class Polygon extends Drawable
{
	ArrayList<Point3f> _vertices;
	ArrayList<Vector3f> _normals;
	ArrayList<TexCoord2f> _textures;
	BoundingBox _boundingBox;
	BoundingSphere _boundingSphere;
	TriangleMesh _triangleMesh;
	
	Material _material;
	
	public Polygon()
	{
		_vertices = new ArrayList<Point3f>();
		_normals = new ArrayList<Vector3f>();
		_textures = new ArrayList<TexCoord2f>();
	}

	public void setMaterial(Material material_)
	{
		_material = material_.clone();
	}
	
	private void initBoundingBox()
	{
		Point3d min = new Point3d(Double.POSITIVE_INFINITY,
                Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
        Point3d max = new Point3d(-Double.POSITIVE_INFINITY,
                -Double.POSITIVE_INFINITY, -Double.POSITIVE_INFINITY);
        for (Point3f p : _vertices)
        {
            if (p.x < min.x)
                min.x = p.x;
            if (p.x > max.x)
                max.x = p.x;
            if (p.y < min.y)
                min.y = p.y;
            if (p.y > max.y)
                max.y = p.y;
            if (p.z < min.z)
                min.z = p.z;
            if (p.z > max.z)
                max.z = p.z;
        }
        _boundingBox = new BoundingBox(this, min, max);
	}
	
	private void initBoundingSphere()
	{
		Point3d origin = new Point3d();
		origin.x = (_boundingBox._minPt.x + _boundingBox._maxPt.x) / 2;
		origin.y = (_boundingBox._minPt.y + _boundingBox._maxPt.y) / 2;
		origin.z = (_boundingBox._minPt.z + _boundingBox._maxPt.z) / 2;
		double radius = -1;
		for (Point3f p : _vertices)
		{
			double d = Util.distance(origin, new Point3d(p.x, p.y, p.z));
			if (d > radius) radius = d;
		}
		_boundingSphere = new BoundingSphere(this, origin, radius);
	}
	
	@Override
	public void draw(GL2 gl)
	{
		if(_material != null)
		{
			gl.glDisable(GL2.GL_COLOR_MATERIAL);
			gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_AMBIENT, _material._ka, 0);
			gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_DIFFUSE, _material._kd, 0);
			gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_SPECULAR, _material._ks, 0);
			gl.glMaterialf(GL2.GL_FRONT, GL2.GL_SHININESS, _material._sh);
		}
		
		gl.glBegin(GL2.GL_POLYGON);
		for (int i = 0; i < _vertices.size(); i++)
		{
			Point3f v = _vertices.get(i);
			if(_normals.size() > 0)
			{
				Vector3f n = _normals.get(i);
				gl.glNormal3f(n.x, n.y, n.z);
			}
			gl.glVertex3f(v.x, v.y, v.z);
		}
		gl.glEnd();
		
		if(_material != null)
		{
			gl.glEnable(GL2.GL_COLOR_MATERIAL);
		}
	}
	
	@Override
	public void build(GL2 gl)
	{
		throw new RuntimeException("should not use this method!");
	}
	
	@Override
	public TriangleMesh getTriangleMesh()
	{
		if (_triangleMesh == null)
		{
			List<TriangleIndex> triangles = new ArrayList<TriangleIndex>();
			for(int i = 2; i < _vertices.size(); i++)
				triangles.add(new TriangleIndex(0, i - 1, i));
			
			List<Point3d> vertices = new ArrayList<Point3d>();
			for(Point3f v : _vertices)
				vertices.add(new Point3d(v.x, v.y, v.z));
			
			_triangleMesh = new TriangleMesh(vertices, triangles);
		}
		return _triangleMesh;
	}
	
    public BoundingBox getBoundingBox()
    {
    	if(_boundingBox == null)
    		initBoundingBox();
        return _boundingBox;
    }
	
	public BoundingSphere getBoundingSphere()
	{
		if(_boundingSphere == null)
    		initBoundingSphere();
		return _boundingSphere;
	}
}